"""
@package profile

Profile analysis of GRASS raster maps and images.

Uses PyPlot (wx.lib.plot.py)

Classes:
 - ProfileFrame
 - SetRasterDialog
 - TextDialog
 - OptDialog

COPYRIGHT: (C) 2007-2008 by the GRASS Development Team
           This program is free software under the GNU General Public
           License (>=v2). Read the file COPYING that comes with GRASS
           for details.

@author Michael Barton
Various updates: Martin Landa <landa.martin gmail.com>
"""

import os
import sys
import math

import wx
import wx.lib.colourselect as  csel

try:
    import wx.lib.plot as plot
except:
    msg= """
    This module requires the NumPy module,
    which could not be imported.  It probably is not installed
    (it's not part of the standard Python distribution). See the
    Numeric Python site (http://numpy.scipy.org) for information on
    downloading source or binaries."""
    print >> sys.stderr, "profile.py: " + msg

import globalvar
try:
    import subprocess
except:
    CompatPath = os.path.join(globalvar.ETCWXDIR)
    sys.path.append(CompatPath)
    from compat import subprocess as subprocess

import render
import menuform
import disp_print
import gselect
import gcmd
import toolbars
from debug import Debug as Debug
from icon import Icons as Icons
from preferences import globalSettings as UserSettings

class ProfileFrame(wx.Frame):
    """
    Mainframe for displaying profile of raster map. Uses wx.lib.plot.
    """

    def __init__(self, parent=None, id=wx.ID_ANY, title=_("Profile Analysis"),
                 rasterList=[],
                 pos=wx.DefaultPosition, size=wx.DefaultSize,
                 style=wx.DEFAULT_FRAME_STYLE):

        self.parent = parent # MapFrame
        self.mapwin = self.parent.MapWindow
        self.Map = render.Map()  # instance of render.Map to be associated with display

        self.pstyledict = { 'solid' : wx.SOLID,
                            'dot' : wx.DOT,
                            'long-dash' : wx.LONG_DASH,
                            'short-dash' : wx.SHORT_DASH,
                            'dot-dash' : wx.DOT_DASH }

        self.ptfilldict = { 'transparent' : wx.TRANSPARENT,
                            'solid' : wx.SOLID }

        wx.Frame.__init__(self, parent, id, title, pos, size, style)

        #
        # Icon
        #
        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCDIR, 'grass_map.ico'), wx.BITMAP_TYPE_ICO))
        
        #
        # Add toolbar
        #
        toolbar = toolbars.ProfileToolbar(parent=self, mapdisplay=self.mapwin, map=self.Map).GetToolbar()
        self.SetToolBar(toolbar)
        
        #
        # Set the size & cursor
        #
        self.SetClientSize(size)

        #
        # Add statusbar
        #
        self.statusbar = self.CreateStatusBar(number=2, style=0)
        self.statusbar.SetStatusWidths([-2, -1])

        #
        # Define canvas
        #
        # plot canvas settings
        self.client = plot.PlotCanvas(self)
        #define the function for drawing pointLabels
        self.client.SetPointLabelFunc(self.DrawPointLabel)
        # Create mouse event for showing cursor coords in status bar
        self.client.canvas.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown)
        # Show closest point when enabled
        self.client.canvas.Bind(wx.EVT_MOTION, self.OnMotion)

        #
        # Init variables
        #
        # 0    -> default raster map to profile
        # 1, 2 -> optional raster map to profile
        # units -> map data units (used for y axis legend)
        self.raster = {}
        for idx in (0, 1, 2):
            self.raster[idx] = {}
            self.raster[idx]['name'] = ''
            self.raster[idx]['units'] = ''
            self.raster[idx]['plegend'] = ''
            # list of distance,value pairs for plotting profile
            self.raster[idx]['datalist'] = []
            # first (default) profile line
            self.raster[idx]['pline'] = None
            self.raster[idx]['prop'] = UserSettings.Get(group='profile', key='raster' + str(idx))

        # set raster map name (if given)
        for idx in range(len(rasterList)):
            self.raster[idx]['name'] = rasterList[idx]

        # string of coordinates for r.profile
        self.coordstr = '' 
        # segment endpoint list
        self.seglist = []
        # list of things to plot
        self.plotlist = []
        # segment endpoints data 
        self.ppoints = '' 
        # plot draw object
        self.profile = None 

        # title of window
        self.ptitle = _('Profile of')

        # determine units (axis labels)
        if self.parent.projinfo['units'] != '':
            self.xlabel = _('Distance (%s)') % self.parent.projinfo['units']
        else:
            self.xlabel = _("Distance along transect")
        self.ylabel = _("Cell values")

        self.properties = {}
        self.properties['font'] = {}
        self.properties['font']['prop'] = UserSettings.Get(group='profile', key='font')
        self.properties['font']['wxfont'] = wx.Font(11, wx.FONTFAMILY_SWISS,
                                                    wx.FONTSTYLE_NORMAL,
                                                    wx.FONTWEIGHT_NORMAL)
        self.properties['marker'] = UserSettings.Get(group='profile', key='marker')

        self.properties['grid'] = UserSettings.Get(group='profile', key='grid')
        
        self.properties['x-axis'] = {}
        self.properties['x-axis']['prop'] = UserSettings.Get(group='profile', key='x-axis')
        self.properties['x-axis']['axis'] = None

        self.properties['y-axis'] = {}
        self.properties['y-axis']['prop'] = UserSettings.Get(group='profile', key='y-axis')
        self.properties['y-axis']['axis'] = None
        self.properties['legend'] = UserSettings.Get(group='profile', key='legend')
        
        # zooming disabled
        self.zoom = False
        # draging disabled
        self.drag = False 

        # vertical and horizontal scrollbars
        self.client.SetShowScrollbars(True)

        # x and y axis set to normal (non-log)
        self.client.setLogScale((False, False)) 
        self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
        self.client.SetYSpec(self.properties['y-axis']['prop']['type'])

        #
        # Bind various events
        #
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

    def OnDrawTransect(self, event):
        """
        Draws transect to profile in map display
        """
        self.mapwin.polycoords = []
        self.seglist = []
        self.mapwin.ClearLines(self.mapwin.pdc)
        self.ppoints = ''

        self.parent.SetFocus()
        self.parent.Raise()
        
        self.mapwin.mouse['use'] = 'profile'
        self.mapwin.mouse['box'] = 'line'
        self.mapwin.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
        self.mapwin.polypen = wx.Pen(colour='dark green', width=2, style=wx.SHORT_DASH)
        self.mapwin.SetCursor(self.Parent.cursors["cross"])

    def OnSelectRaster(self, event):
        """
        Select raster map(s) to profile
        """
        dlg = SetRasterDialog(parent=self)

        if dlg.ShowModal() == wx.ID_OK:
            for r in self.raster.keys():
                self.raster[r]['name'] = dlg.raster[r]['name']

            # plot profile
            if self.raster[0]['name'] and len(self.mapwin.polycoords) > 0:
                self.OnCreateProfile(event=None)

        dlg.Destroy()

    def SetRaster(self):
        """
        Create coordinate string for profiling. Create segment list for
        transect segment markers.
        """

        #
        # create list of coordinate points for r.profile
        #
        dist = 0
        cumdist = 0
        self.coordstr = ''
        lasteast = lastnorth = None

        if len(self.mapwin.polycoords) > 0:
            for point in self.mapwin.polycoords:
                # build string of coordinate points for r.profile
                if self.coordstr == '':
                    self.coordstr = '%d,%d' % (point[0], point[1])
                else:
                    self.coordstr = '%s,%d,%d' % (self.coordstr, point[0], point[1])

        if self.raster[0]['name'] == '':
            return

        # title of window
        self.ptitle = _('Profile of')

        #
        # create datalist for each raster map
        #
        for r in self.raster.itervalues():
            if r['name'] == '':
                continue
            r['datalist'] = self.CreateDatalist(r['name'], self.coordstr)
            r['plegend'] = _('Profile of %s') % r['name']


            p = gcmd.Command(['r.info',
                              'map=%s' % r['name'],
                              '-u',
                              '--quiet'])
            r['units'] = p.ReadStdOutput()[0].split('=')[1]

            # update title
            self.ptitle += ' %s and' % r['name']

        self.ptitle = self.ptitle.rstrip('and')
        
        #
        # set ylabel to match units if they exist
        #
        self.ylabel = ''
        i = 0
        for r in self.raster.itervalues():
            if r['name'] == '':
                continue
            if r['units'] != '':
                self.ylabel = '%s (%d),' % (r['units'], i)
            i += 1
        if self.ylabel == '':
            self.ylabel = _('Raster values')
        else:
            self.ylabel = self.ylabel.rstrip(',')

        #
        # create list of coordinates for transect segment markers
        #
        if len(self.mapwin.polycoords) > 0:
            for point in self.mapwin.polycoords:
                # get value of raster cell at coordinate point
                p = gcmd.Command(['r.what',
                                  'input=%s' % self.raster[0]['name'],
                                  'east_north=%d,%d' % (point[0],point[1])])
                outlist = p.ReadStdOutput()
                val = outlist[0].split('|')[3]
                
                # calculate distance between coordinate points
                if lasteast and lastnorth:
                    dist = math.sqrt(math.pow((lasteast-point[0]),2) + math.pow((lastnorth-point[1]),2))
                cumdist += dist

                # build a list of distance,value pairs for each segment of transect
                self.seglist.append((cumdist,val))
                lasteast = point[0]
                lastnorth = point[1]

            # delete first and last segment point
            try:
                self.seglist.pop(0)
                self.seglist.pop()
            except:
                pass

    def SetGraphStyle(self):
        """
        Set plot and text options
        """
        self.client.SetFont(self.properties['font']['wxfont'])
        self.client.SetFontSizeTitle(self.properties['font']['prop']['titleSize'])
        self.client.SetFontSizeAxis(self.properties['font']['prop']['axisSize'])

        self.client.SetEnableZoom(self.zoom)
        self.client.SetEnableDrag(self.drag)
        
        #
        # axis settings
        #
        if self.properties['x-axis']['prop']['type'] == 'custom':
            self.client.SetXSpec('min')
        else:
            self.client.SetXSpec(self.properties['x-axis']['prop']['type'])

        if self.properties['y-axis']['prop']['type'] == 'custom':
            self.client.SetYSpec('min')
        else:
            self.client.SetYSpec(self.properties['y-axis']['prop']['type'])

        if self.properties['x-axis']['prop']['type'] == 'custom' and \
               self.properties['x-axis']['prop']['min'] < self.properties['x-axis']['prop']['max']:
            self.properties['x-axis']['axis'] = (self.properties['x-axis']['prop']['min'],
                                                 self.properties['x-axis']['prop']['max'])
        else:
            self.properties['x-axis']['axis'] = None

        if self.properties['y-axis']['prop']['type'] == 'custom' and \
                self.properties['y-axis']['prop']['min'] < self.properties['y-axis']['prop']['max']:
            self.properties['y-axis']['axis'] = (self.properties['y-axis']['prop']['min'],
                                                 self.properties['y-axis']['prop']['max'])
        else:
            self.properties['y-axis']['axis'] = None

        self.client.SetEnableGrid(self.properties['grid']['enabled'])
        self.client.SetGridColour(wx.Color(self.properties['grid']['color'][0],
                                           self.properties['grid']['color'][1],
                                           self.properties['grid']['color'][2],
                                           255))

        self.client.SetFontSizeLegend(self.properties['font']['prop']['legendSize'])
        self.client.SetEnableLegend(self.properties['legend']['enabled'])

        if self.properties['x-axis']['prop']['log'] == True:
            self.properties['x-axis']['axis'] = None
            self.client.SetXSpec('min')
        if self.properties['y-axis']['prop']['log'] == True:
            self.properties['y-axis']['axis'] = None
            self.client.SetYSpec('min')
            
        self.client.setLogScale((self.properties['x-axis']['prop']['log'],
                                 self.properties['y-axis']['prop']['log']))

        # self.client.SetPointLabelFunc(self.DrawPointLabel())

    def CreateDatalist(self, raster, coords):
        """
        Build a list of distance, value pairs for points along transect
        """
        datalist = []
        try:
            cmdlist = ['r.profile',
                       'input=%s' % raster,
                       'profile=%s' % coords,
                       'null=nan',
                       '--quiet']
            p = gcmd.Command(cmdlist)
            for outline in p.ReadStdOutput():
                dist, elev = outline.split(' ')
                datalist.append((dist,elev))

            return datalist
        except gcmd.CmdError, e:
            print e
            return None

    def OnCreateProfile(self, event):
        """
        Main routine for creating a profile. Uses r.profile to create a list
        of distance,cell value pairs. This is passed to plot to create a
        line graph of the profile. If the profile transect is in multiple
        segments, these are drawn as points. Profile transect is drawn, using
        methods in mapdisp.py
        """
        if len(self.mapwin.polycoords) == 0 or self.raster[0]['name'] == '':
            dlg = wx.MessageDialog(parent=self,
                                   message=_('You must draw a transect to profile in the map display window.'),
                                   caption=_('Nothing to profile'),
                                   style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
            dlg.ShowModal()
            dlg.Destroy()
            return

        self.mapwin.SetCursor(self.parent.cursors["default"])
        self.SetCursor(self.parent.cursors["default"])
        self.SetGraphStyle()

        self.SetRaster()
            
        self.DrawPlot()

        # reset transect
        self.mapwin.mouse['begin'] = self.mapwin.mouse['end'] = (0.0,0.0)
        self.mapwin.mouse['use'] = 'pointer'
        self.mapwin.mouse['box'] = 'point'

    def DrawPlot(self):
        """
        Draw line and point plot from transect datalist and
        transect segment endpoint coordinates.
        """

        # graph the distance, value pairs for the transect
        self.plotlist = []
        for r in self.raster.itervalues():
            if len(r['datalist']) > 0:
                col = wx.Color(r['prop']['pcolor'][0],
                               r['prop']['pcolor'][1],
                               r['prop']['pcolor'][2],
                               255)
                r['pline'] = plot.PolyLine(r['datalist'],
                                           colour=col,
                                           width=r['prop']['pwidth'],
                                           style=self.pstyledict[r['prop']['pstyle']],
                                           legend=r['plegend'])

                self.plotlist.append(r['pline'])

        if len(self.seglist) > 0 :
            self.ppoints = plot.PolyMarker(self.seglist,
                                           legend=' ' + self.properties['marker']['legend'],
                                           colour=wx.Color(self.properties['marker']['color'][0],
                                                           self.properties['marker']['color'][1],
                                                           self.properties['marker']['color'][2],
                                                           255),
                                           size=self.properties['marker']['size'],
                                           fillstyle=self.ptfilldict[self.properties['marker']['fill']],
                                           marker=self.properties['marker']['type'])
            self.plotlist.append(self.ppoints)

        self.profile = plot.PlotGraphics(self.plotlist,
                                         self.ptitle,
                                         self.xlabel,
                                         self.ylabel)

        if self.properties['x-axis']['prop']['type'] == 'custom':
            self.client.SetXSpec('min')
        else:
            self.client.SetXSpec(self.properties['x-axis']['prop']['type'])

        if self.properties['y-axis']['prop']['type'] == 'custom':
            self.client.SetYSpec('min')
        else:
            self.client.SetYSpec(self.properties['y-axis']['prop']['type'])

        self.client.Draw(self.profile, self.properties['x-axis']['axis'],
                         self.properties['y-axis']['axis'])

    def OnZoom(self, event):
        """
        Enable zooming and disable dragging
        """

        self.zoom = True
        self.drag = False
        self.client.SetEnableZoom(self.zoom)
        self.client.SetEnableDrag(self.drag)

    def OnDrag(self, event):
        """
        Enable dragging and disable zooming
        """

        self.zoom = False
        self.drag = True
        self.client.SetEnableDrag(self.drag)
        self.client.SetEnableZoom(self.zoom)

    def OnRedraw(self, event):
        """
        Redraw the profile window. Unzoom to original size
        """
        self.client.Reset()
        self.client.Redraw()

    def Update(self):
        """
        Update profile after changing options
        """

        self.SetGraphStyle()
        self.DrawPlot()

    def OnErase(self, event):
        """
        Erase the profile window
        """
        self.client.Clear()
        self.mapwin.ClearLines(self.mapwin.pdc)
        self.mapwin.ClearLines(self.mapwin.pdcTmp)
        self.mapwin.polycoords = []
        self.mapwin.Refresh()
        #        try:
        #            self.mapwin.pdc.ClearId(self.mapwin.lineid)
        #            self.mapwin.pdc.ClearId(self.mapwin.plineid)
        #            self.mapwin.Refresh()
        #        except:
        #            pass

    def SaveToFile(self, event):
        """
        Save profile to graphics file
        """
        self.client.SaveFile()

    def DrawPointLabel(self, dc, mDataDict):
        """This is the fuction that defines how the pointLabels are plotted
            dc - DC that will be passed
            mDataDict - Dictionary of data that you want to use for the pointLabel

            As an example I have decided I want a box at the curve point
            with some text information about the curve plotted below.
            Any wxDC method can be used.
        """
        # ----------
        dc.SetPen(wx.Pen(wx.BLACK))
        dc.SetBrush(wx.Brush( wx.BLACK, wx.SOLID ) )

        sx, sy = mDataDict["scaledXY"] #scaled x,y of closest point
        dc.DrawRectangle( sx-5,sy-5, 10, 10)  #10by10 square centered on point
        px,py = mDataDict["pointXY"]
        cNum = mDataDict["curveNum"]
        pntIn = mDataDict["pIndex"]
        legend = mDataDict["legend"]
        #make a string to display
        s = "Crv# %i, '%s', Pt. (%.2f,%.2f), PtInd %i" %(cNum, legend, px, py, pntIn)
        dc.DrawText(s, sx , sy+1)
        # -----------

    def OnMouseLeftDown(self,event):
        s= "Left Mouse Down at Point: (%.4f, %.4f)" % self.client._getXY(event)
        self.SetStatusText(s)
        event.Skip()            #allows plotCanvas OnMouseLeftDown to be called

    def OnMotion(self, event):
        # indicate when mouse is outside the plot area
        if self.client.OnLeave(event): print 'out of area'
        #show closest point (when enbled)
        if self.client.GetEnablePointLabel() == True:
            #make up dict with info for the pointLabel
            #I've decided to mark the closest point on the closest curve
            dlst= self.client.GetClosetPoint( self.client._getXY(event), pointScaled= True)
            if dlst != []:      #returns [] if none
                curveNum, legend, pIndex, pointXY, scaledXY, distance = dlst
                #make up dictionary to pass to my user function (see DrawPointLabel)
                mDataDict= {"curveNum":curveNum, "legend":legend, "pIndex":pIndex,\
                    "pointXY":pointXY, "scaledXY":scaledXY}
                #pass dict to update the pointLabel
                self.client.UpdatePointLabel(mDataDict)
        event.Skip()           #go to next handler

    def ProfileOptionsMenu(self, event):
        """
        Popup menu for profile and text options
        """

        point = wx.GetMousePosition()
        popt = wx.Menu()
        # Add items to the menu
        settext = wx.MenuItem(popt, -1, 'Profile text settings')
        popt.AppendItem(settext)
        self.Bind(wx.EVT_MENU, self.PText, settext)

        setgrid = wx.MenuItem(popt, -1, 'Profile plot settings')
        popt.AppendItem(setgrid)
        self.Bind(wx.EVT_MENU, self.POptions, setgrid)

        # Popup the menu.  If an item is selected then its handler
        # will be called before PopupMenu returns.
        self.PopupMenu(popt)
        popt.Destroy()

    def NotFunctional(self):
        """
        Creates a 'not functional' message dialog
        """

        dlg = wx.MessageDialog(self, 'This feature is not yet functional',
                           'Under Construction', wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def PText(self, event):
        """
        Set custom text values for profile
        title and axis labels.
        """
        dlg = TextDialog(parent=self, id=wx.ID_ANY, title=_('Profile text settings'))

        if dlg.ShowModal() == wx.ID_OK:
            self.ptitle = dlg.ptitle
            self.xlabel = dlg.xlabel
            self.ylabel = dlg.ylabel
            dlg.UpdateSettings()

            self.client.SetFont(self.properties['font']['wxfont'])
            self.client.SetFontSizeTitle(self.properties['font']['prop']['titleSize'])
            self.client.SetFontSizeAxis(self.properties['font']['prop']['axisSize'])

            if self.profile:
                self.profile.setTitle(dlg.ptitle)
                self.profile.setXLabel(dlg.xlabel)
                self.profile.setYLabel(dlg.ylabel)

        dlg.Destroy()

        self.OnRedraw(event=None)

    def POptions(self, event):
        """
        Set various profile options, including: line width, color, style;
        marker size, color, fill, and style; grid and legend options.
        Calls OptDialog class.
        """
        dlg = OptDialog(parent=self, id=wx.ID_ANY, title=_('Profile settings'))

        if dlg.ShowModal() == wx.ID_OK:
            dlg.UpdateSettings()

            self.SetGraphStyle()
            if self.profile:
                self.DrawPlot()

        dlg.Destroy()

    def PrintMenu(self, event):
        """
        Print options and output menu
        """
        point = wx.GetMousePosition()
        printmenu = wx.Menu()
        # Add items to the menu
        setup = wx.MenuItem(printmenu, -1,'Page setup')
        printmenu.AppendItem(setup)
        self.Bind(wx.EVT_MENU, self.OnPageSetup, setup)

        preview = wx.MenuItem(printmenu, -1,'Print preview')
        printmenu.AppendItem(preview)
        self.Bind(wx.EVT_MENU, self.OnPrintPreview, preview)

        doprint = wx.MenuItem(printmenu, -1,'Print display')
        printmenu.AppendItem(doprint)
        self.Bind(wx.EVT_MENU, self.OnDoPrint, doprint)

        # Popup the menu.  If an item is selected then its handler
        # will be called before PopupMenu returns.
        self.PopupMenu(printmenu)
        printmenu.Destroy()

    def OnPageSetup(self, event):
        self.client.PageSetup()

    def OnPrintPreview(self, event):
        self.client.PrintPreview()

    def OnDoPrint(self, event):
        self.client.Printout()

    def OnQuit(self, event):
        self.Close(True)

    def OnCloseWindow(self, event):
        """
        Close profile window and clean up
        """
        self.mapwin.ClearLines()
        self.mapwin.mouse['begin'] = self.mapwin.mouse['end'] = (0.0, 0.0)
        self.mapwin.mouse['use'] = 'pointer'
        self.mapwin.mouse['box'] = 'point'
        self.mapwin.polycoords = []
        self.mapwin.SetCursor(self.Parent.cursors["default"])

        self.mapwin.UpdateMap(render=False, renderVector=False)

        self.Destroy()

class SetRasterDialog(wx.Dialog):
    def __init__(self, parent, id=wx.ID_ANY, title=_("Select raster map to profile"),
                 pos=wx.DefaultPosition, size=wx.DefaultSize,
                 style=wx.DEFAULT_DIALOG_STYLE):
        """
        Dialog to select raster maps to profile.
        """

        wx.Dialog.__init__(self, parent, id, title, pos, size, style)

        self.parent = parent
        self.coordstr = self.parent.coordstr

        #         if self.coordstr == '':
        #             dlg = wx.MessageDialog(parent=self,
        #                                    message=_('You must draw a transect to profile in the map display window.'),
        #                                    caption=_('Nothing to profile'),
        #                                    style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
        #             dlg.ShowModal()
        #             dlg.Destroy()
        #             self.Close(True)
        #             return

        self.raster = { 0 : { 'name' : self.parent.raster[0]['name'],
                              'id' : None },
                        1 : { 'name' : self.parent.raster[1]['name'],
                              'id' : None },
                        2 : { 'name' : self.parent.raster[2]['name'],
                              'id' : None }
                        }

        sizer = wx.BoxSizer(wx.VERTICAL)

        box = wx.GridBagSizer (hgap=3, vgap=3)
        
        i = 0
        for txt in [_("Select raster map 1 (required):"),
                    _("Select raster map 2 (optional):"),
                    _("Select raster map 3 (optional):")]:
            label = wx.StaticText(parent=self, id=wx.ID_ANY, label=txt)
            box.Add(item=label,
                    flag=wx.ALIGN_CENTER_VERTICAL, pos=(i, 0))
            
            selection = gselect.Select(self, id=wx.ID_ANY,
                                       size=globalvar.DIALOG_GSELECT_SIZE,
                                       type='cell')
            selection.SetValue(str(self.raster[i]['name']))
            self.raster[i]['id'] = selection.GetChildren()[0].GetId()
            selection.Bind(wx.EVT_TEXT, self.OnSelection)
            
            box.Add(item=selection, pos=(i, 1))
            
            i += 1 
            
        sizer.Add(item=box, proportion=0,
                  flag=wx.ALL, border=10)

        line = wx.StaticLine(parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL)
        sizer.Add(item=line, proportion=0,
                  flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border=5)

        btnsizer = wx.StdDialogButtonSizer()

        btn = wx.Button(self, wx.ID_OK)
        btn.SetDefault()
        btnsizer.AddButton(btn)

        btn = wx.Button(self, wx.ID_CANCEL)
        btnsizer.AddButton(btn)
        btnsizer.Realize()

        sizer.Add(item=btnsizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)

        self.SetSizer(sizer)
        sizer.Fit(self)

    def OnSelection(self, event):
        id = event.GetId()
        for r in self.raster.itervalues():
            if r['id'] == id:
                r['name'] = event.GetString()
                break

class TextDialog(wx.Dialog):
    def __init__(self, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize,
                 style=wx.DEFAULT_DIALOG_STYLE):
        wx.Dialog.__init__(self, parent, id, title, pos, size, style)
        """
        Dialog to set profile text options: font, title
        and font size, axis labels and font size
        """
        #
        # initialize variables
        #
        # combo box entry lists
        self.ffamilydict = { 'default' : wx.FONTFAMILY_DEFAULT,
                             'decorative' : wx.FONTFAMILY_DECORATIVE,
                             'roman' : wx.FONTFAMILY_ROMAN,
                             'script' : wx.FONTFAMILY_SCRIPT,
                             'swiss' : wx.FONTFAMILY_SWISS,
                             'modern' : wx.FONTFAMILY_MODERN,
                             'teletype' : wx.FONTFAMILY_TELETYPE }

        self.fstyledict = { 'normal' : wx.FONTSTYLE_NORMAL,
                            'slant' : wx.FONTSTYLE_SLANT,
                            'italic' : wx.FONTSTYLE_ITALIC }

        self.fwtdict = { 'normal' : wx.FONTWEIGHT_NORMAL,
                         'light' : wx.FONTWEIGHT_LIGHT,
                         'bold' : wx.FONTWEIGHT_BOLD }

        self.parent = parent

        self.ptitle = self.parent.ptitle
        self.xlabel = self.parent.xlabel
        self.ylabel = self.parent.ylabel

        self.properties = self.parent.properties # read-only
        
        # font size
        self.fontfamily = self.properties['font']['wxfont'].GetFamily()
        self.fontstyle = self.properties['font']['wxfont'].GetStyle()
        self.fontweight = self.properties['font']['wxfont'].GetWeight()

        self._do_layout()
        
    def _do_layout(self):
        """Do layout"""
        # dialog layout
        sizer = wx.BoxSizer(wx.VERTICAL)

        box = wx.StaticBox(parent=self, id=wx.ID_ANY,
                           label=" %s " % _("Text settings"))
        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
        gridSizer = wx.GridBagSizer(vgap=5, hgap=5)

        #
        # profile title
        #
        label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Profile title:"))
        gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
        self.ptitleentry = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(200,-1))
        # self.ptitleentry.SetFont(self.font)
        self.ptitleentry.SetValue(self.ptitle)
        gridSizer.Add(item=self.ptitleentry, pos=(0, 1))

        #
        # title font
        #
        tlabel = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Title font size (pts):"))
        gridSizer.Add(item=tlabel, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
        self.ptitlesize = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="", pos=(30, 50),
                                      size=(50,-1), style=wx.SP_ARROW_KEYS)
        self.ptitlesize.SetRange(5,100)
        self.ptitlesize.SetValue(int(self.properties['font']['prop']['titleSize']))
        gridSizer.Add(item=self.ptitlesize, pos=(1, 1))

        #
        # x-axis label
        #
        label = wx.StaticText(parent=self, id=wx.ID_ANY, label=("X-axis label:"))
        gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(2, 0))
        self.xlabelentry = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(200,-1))
        # self.xlabelentry.SetFont(self.font)
        self.xlabelentry.SetValue(self.xlabel)
        gridSizer.Add(item=self.xlabelentry, pos=(2, 1))

        #
        # y-axis label
        #
        label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Y-axis label:"))
        gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(3, 0))
        self.ylabelentry = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(200,-1))
        # self.ylabelentry.SetFont(self.font)
        self.ylabelentry.SetValue(self.ylabel)
        gridSizer.Add(item=self.ylabelentry, pos=(3, 1))

        #
        # font size
        #
        llabel = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Label font size (pts):"))
        gridSizer.Add(item=llabel, flag=wx.ALIGN_CENTER_VERTICAL, pos=(4, 0))
        self.axislabelsize = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="", pos=(30, 50),
                                         size=(50, -1), style=wx.SP_ARROW_KEYS)
        self.axislabelsize.SetRange(5, 100) 
        self.axislabelsize.SetValue(int(self.properties['font']['prop']['axisSize']))
        gridSizer.Add(item=self.axislabelsize, pos=(4,1))

        boxSizer.Add(item=gridSizer)
        sizer.Add(item=boxSizer, flag=wx.ALL | wx.EXPAND, border=3)

        #
        # font settings
        #
        box = wx.StaticBox(parent=self, id=wx.ID_ANY,
                           label=" %s " % _("Font settings"))
        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
        gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
        gridSizer.AddGrowableCol(1)

        #
        # font family
        #
        label1 = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Font family:"))
        gridSizer.Add(item=label1, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
        self.ffamilycb = wx.ComboBox(parent=self, id=wx.ID_ANY, size=(200, -1),
                                choices=self.ffamilydict.keys(), style=wx.CB_DROPDOWN)
        self.ffamilycb.SetStringSelection('swiss')
        for item in self.ffamilydict.items():
            if self.fontfamily == item[1]:
                self.ffamilycb.SetStringSelection(item[0])
                break
        gridSizer.Add(item=self.ffamilycb, pos=(0, 1), flag=wx.ALIGN_RIGHT)

        #
        # font style
        #
        label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Style:"))
        gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
        self.fstylecb = wx.ComboBox(parent=self, id=wx.ID_ANY, size=(200, -1),
                                    choices=self.fstyledict.keys(), style=wx.CB_DROPDOWN)
        self.fstylecb.SetStringSelection('normal')
        for item in self.fstyledict.items():
            if self.fontstyle == item[1]:
                self.fstylecb.SetStringSelection(item[0])
                break
        gridSizer.Add(item=self.fstylecb, pos=(1, 1), flag=wx.ALIGN_RIGHT)

        #
        # font weight
        #
        label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Weight:"))
        gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(2, 0))
        self.fwtcb = wx.ComboBox(parent=self, size=(200, -1),
                                 choices=self.fwtdict.keys(), style=wx.CB_DROPDOWN)
        self.fwtcb.SetStringSelection('normal')
        for item in self.fwtdict.items():
            if self.fontweight == item[1]:
                self.fwtcb.SetStringSelection(item[0])
                break

        gridSizer.Add(item=self.fwtcb, pos=(2, 1), flag=wx.ALIGN_RIGHT)
                      
        boxSizer.Add(item=gridSizer, flag=wx.EXPAND)
        sizer.Add(item=boxSizer, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)

        line = wx.StaticLine(parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL)
        sizer.Add(item=line, proportion=0,
                  flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border=3)

        #
        # buttons
        #
        btnSave = wx.Button(self, wx.ID_SAVE)
        btnApply = wx.Button(self, wx.ID_APPLY)
        btnCancel = wx.Button(self, wx.ID_CANCEL)
        btnSave.SetDefault()

        # bindigs
        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
        btnApply.SetToolTipString(_("Apply changes for the current session"))
        btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
        btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
        btnSave.SetDefault()
        btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
        btnCancel.SetToolTipString(_("Close dialog and ignore changes"))

        # sizers
        btnStdSizer = wx.StdDialogButtonSizer()
        btnStdSizer.AddButton(btnCancel)
        btnStdSizer.AddButton(btnSave)
        btnStdSizer.AddButton(btnApply)
        btnStdSizer.Realize()
        
        sizer.Add(item=btnStdSizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)

        #
        # bindings
        #
        self.ptitleentry.Bind(wx.EVT_TEXT, self.OnTitle)
        self.xlabelentry.Bind(wx.EVT_TEXT, self.OnXLabel)
        self.ylabelentry.Bind(wx.EVT_TEXT, self.OnYLabel)

        self.SetSizer(sizer)
        sizer.Fit(self)

    def OnTitle(self, event):
        self.ptitle = event.GetString()

    def OnXLabel(self, event):
        self.xlabel = event.GetString()

    def OnYLabel(self, event):
        self.ylabel = event.GetString()

    def UpdateSettings(self):
        self.properties['font']['prop']['titleSize'] = self.ptitlesize.GetValue()
        self.properties['font']['prop']['axisSize'] = self.axislabelsize.GetValue()

        family = self.ffamilydict[self.ffamilycb.GetStringSelection()]
        self.properties['font']['wxfont'].SetFamily(family)
        style = self.fstyledict[self.fstylecb.GetStringSelection()]
        self.properties['font']['wxfont'].SetStyle(style)
        weight = self.fwtdict[self.fwtcb.GetStringSelection()]
        self.properties['font']['wxfont'].SetWeight(weight)

    def OnSave(self, event):
        """Button 'Save' pressed"""
        self.UpdateSettings()
        fileSettings = {}
        UserSettings.ReadSettingsFile(settings=fileSettings)
        fileSettings['profile'] = UserSettings.Get(group='profile')
        file = UserSettings.SaveToFile(fileSettings)
        self.parent.parent.gismanager.goutput.WriteLog(_('Profile settings saved to file \'%s\'.') % file)
        self.Close()

    def OnApply(self, event):
        """Button 'Apply' pressed"""
        self.UpdateSettings()
        self.Close()

    def OnCancel(self, event):
        """Button 'Cancel' pressed"""
        self.Close()
        
class OptDialog(wx.Dialog):
    def __init__(self, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize,
            style=wx.DEFAULT_DIALOG_STYLE):
        wx.Dialog.__init__(self, parent, id, title, pos, size, style)
        """
        Dialog to set various profile options, including: line width, color, style;
        marker size, color, fill, and style; grid and legend options.
        """
        # init variables
        self.pstyledict = parent.pstyledict
        self.ptfilldict = parent.ptfilldict

        self.pttypelist = ['circle',
                           'dot',
                           'square',
                           'triangle',
                           'triangle_down',
                           'cross',
                           'plus']
        
        self.axislist = ['min',
                         'auto',
                         'custom']

        # widgets ids
        self.wxId = {}
        
        self.parent = parent

        # read-only
        self.raster = self.parent.raster
        self.properties = self.parent.properties
        
        self._do_layout()

    def _do_layout(self):
        """Do layout"""
        # dialog layout
        sizer = wx.BoxSizer(wx.VERTICAL)

        #
        # profile line settings
        #
        box = wx.StaticBox(parent=self, id=wx.ID_ANY,
                           label=" %s " % _("Profile line settings"))
        boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)

        idx = 1
        self.wxId['pcolor'] = []
        self.wxId['pwidth'] = []
        self.wxId['pstyle'] = []
        self.wxId['plegend'] = []
        for r in self.raster.itervalues():
            box = wx.StaticBox(parent=self, id=wx.ID_ANY,
                               label=" %s %d " % (_("Profile"), idx))
            boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
            
            gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
            row = 0            
            label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Line color"))
            gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
            pcolor = csel.ColourSelect(parent=self, id=wx.ID_ANY, colour=r['prop']['pcolor'])
            self.wxId['pcolor'].append(pcolor.GetId())
            gridSizer.Add(item=pcolor, pos=(row, 1))

            row += 1
            label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Line width"))
            gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
            pwidth = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="",
                                 size=(50,-1), style=wx.SP_ARROW_KEYS)
            pwidth.SetRange(1, 10)
            pwidth.SetValue(r['prop']['pwidth'])
            self.wxId['pwidth'].append(pwidth.GetId())
            gridSizer.Add(item=pwidth, pos=(row, 1))

            row +=1
            label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Line style"))
            gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
            pstyle = wx.ComboBox(parent=self, id=wx.ID_ANY, 
                                 size=(120, -1), choices=self.pstyledict.keys(), style=wx.CB_DROPDOWN)
            pstyle.SetStringSelection(r['prop']['pstyle'])
            self.wxId['pstyle'].append(pstyle.GetId())
            gridSizer.Add(item=pstyle, pos=(row, 1))

            row += 1
            label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Legend"))
            gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
            plegend = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(200,-1))
            plegend.SetValue(r['plegend'])
            gridSizer.Add(item=plegend, pos=(row, 1))
            self.wxId['plegend'].append(plegend.GetId())
            boxSizer.Add(item=gridSizer)

            if idx == 0:
                flag = wx.ALL
            else:
                flag = wx.TOP | wx.BOTTOM | wx.RIGHT
            boxMainSizer.Add(item=boxSizer, flag=flag, border=3)

            idx += 1
            
        sizer.Add(item=boxMainSizer, flag=wx.ALL | wx.EXPAND, border=3)

        middleSizer = wx.BoxSizer(wx.HORIZONTAL)
        
        #
        # segment marker settings
        #
        box = wx.StaticBox(parent=self, id=wx.ID_ANY,
                           label=" %s " % _("Transect segment marker settings"))
        boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)

        self.wxId['marker'] = {}
        gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
        label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Color"))
        gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
        ptcolor = csel.ColourSelect(parent=self, id=wx.ID_ANY, colour=self.properties['marker']['color'])
        self.wxId['marker']['color'] = ptcolor.GetId()
        gridSizer.Add(item=ptcolor, pos=(0, 1))

        label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Size"))
        gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
        ptsize = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="",
                             size=(50, -1), style=wx.SP_ARROW_KEYS)
        ptsize.SetRange(1, 10)
        ptsize.SetValue(self.properties['marker']['size'])
        self.wxId['marker']['size'] = ptsize.GetId()
        gridSizer.Add(item=ptsize, pos=(1, 1))
        
        label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Style"))
        gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(2, 0))
        ptfill = wx.ComboBox(parent=self, id=wx.ID_ANY,
                             size=(120, -1), choices=self.ptfilldict.keys(), style=wx.CB_DROPDOWN)
        ptfill.SetStringSelection(self.properties['marker']['fill'])
        self.wxId['marker']['fill'] = ptfill.GetId()
        gridSizer.Add(item=ptfill, pos=(2, 1))
        
        label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Legend"))
        gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(3, 0))
        ptlegend = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(200,-1))
        ptlegend.SetValue(self.properties['marker']['legend'])
        self.wxId['marker']['legend'] = ptlegend.GetId()
        gridSizer.Add(item=ptlegend, pos=(3, 1))
                
        label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Type"))
        gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(4, 0))
        pttype = wx.ComboBox(parent=self, 
                             size=(200, -1), choices=self.pttypelist, style=wx.CB_DROPDOWN)
        pttype.SetStringSelection(self.properties['marker']['type'])
        self.wxId['marker']['type'] = pttype.GetId()
        gridSizer.Add(item=pttype, pos=(4, 1))

        boxMainSizer.Add(item=gridSizer, flag=wx.ALL, border=3)
        middleSizer.Add(item=boxMainSizer, flag=wx.ALL | wx.EXPAND, border=3)

        #
        # axis options
        #
        box = wx.StaticBox(parent=self, id=wx.ID_ANY,
                           label=" %s " % _("Axis settings"))
        boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)

        self.wxId['x-axis'] = {}
        self.wxId['y-axis'] = {}
        idx = 0
        for axis, atype in [(_("X-Axis"), 'x-axis'),
                     (_("Y-Axis"), 'y-axis')]:
            box = wx.StaticBox(parent=self, id=wx.ID_ANY,
                               label=" %s " % axis)
            boxSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
            gridSizer = wx.GridBagSizer(vgap=5, hgap=5)

            prop = self.properties[atype]['prop']
            
            row = 0
            label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Style"))
            gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
            type = wx.ComboBox(parent=self, id=wx.ID_ANY,
                               size=(100, -1), choices=self.axislist, style=wx.CB_DROPDOWN)
            type.SetStringSelection(prop['type']) 
            self.wxId[atype]['type'] = type.GetId()
            gridSizer.Add(item=type, pos=(row, 1))
            
            row += 1
            label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Custom min"))
            gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
            min = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(70, -1))
            min.SetValue(str(prop['min']))
            self.wxId[atype]['min'] = min.GetId()
            gridSizer.Add(item=min, pos=(row, 1))

            row += 1
            label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Custom max"))
            gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
            max = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(70, -1))
            max.SetValue(str(prop['max']))
            self.wxId[atype]['max'] = max.GetId()
            gridSizer.Add(item=max, pos=(row, 1))
            
            row += 1
            log = wx.CheckBox(parent=self, id=wx.ID_ANY, label=_("Log scale"))
            log.SetValue(prop['log'])
            self.wxId[atype]['log'] = log.GetId()
            gridSizer.Add(item=log, pos=(row, 0), span=(1, 2))

            if idx == 0:
                flag = wx.ALL | wx.EXPAND
            else:
                flag = wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND

            boxSizer.Add(item=gridSizer, flag=wx.ALL, border=3)
            boxMainSizer.Add(item=boxSizer, flag=flag, border=3)

            idx += 1
            
        middleSizer.Add(item=boxMainSizer, flag=wx.ALL | wx.EXPAND, border=3)

        #
        # grid & legend options
        #
        self.wxId['grid'] = {}
        self.wxId['legend'] = {}
        self.wxId['font'] = {}
        box = wx.StaticBox(parent=self, id=wx.ID_ANY,
                           label=" %s " % _("Grid and Legend settings"))
        boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
        gridSizer = wx.GridBagSizer(vgap=5, hgap=5)

        row = 0
        label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Grid color"))
        gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
        gridcolor = csel.ColourSelect(parent=self, id=wx.ID_ANY, colour=self.properties['grid']['color'])
        self.wxId['grid']['color'] = gridcolor.GetId()
        gridSizer.Add(item=gridcolor, pos=(row, 1))

        row +=1
        gridshow = wx.CheckBox(parent=self, id=wx.ID_ANY, label=_("Show grid"))
        gridshow.SetValue(self.properties['grid']['enabled'])
        self.wxId['grid']['enabled'] = gridshow.GetId()
        gridSizer.Add(item=gridshow, pos=(row, 0), span=(1, 2))

        row +=1
        label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Legend font size"))
        gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
        legendfontsize = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="", 
                                     size=(50, -1), style=wx.SP_ARROW_KEYS)
        legendfontsize.SetRange(5,100)
        legendfontsize.SetValue(int(self.properties['font']['prop']['legendSize']))
        self.wxId['font']['legendSize'] = legendfontsize.GetId()
        gridSizer.Add(item=legendfontsize, pos=(row, 1))

        row += 1
        legendshow = wx.CheckBox(parent=self, id=wx.ID_ANY, label=_("Show legend"))
        legendshow.SetValue(self.properties['legend']['enabled'])
        self.wxId['legend']['enabled'] = legendshow.GetId()
        gridSizer.Add(item=legendshow, pos=(row, 0), span=(1, 2))

        boxMainSizer.Add(item=gridSizer, flag=flag, border=3)

        middleSizer.Add(item=boxMainSizer, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)

        sizer.Add(item=middleSizer, flag=wx.ALL, border=0)
        
        #
        # line & buttons
        #
        line = wx.StaticLine(parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL)
        sizer.Add(item=line, proportion=0,
                  flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border=3)

        #
        # buttons
        #
        btnSave = wx.Button(self, wx.ID_SAVE)
        btnApply = wx.Button(self, wx.ID_APPLY)
        btnCancel = wx.Button(self, wx.ID_CANCEL)
        btnSave.SetDefault()

        # bindigs
        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
        btnApply.SetToolTipString(_("Apply changes for the current session"))
        btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
        btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
        btnSave.SetDefault()
        btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
        btnCancel.SetToolTipString(_("Close dialog and ignore changes"))

        # sizers
        btnStdSizer = wx.StdDialogButtonSizer()
        btnStdSizer.AddButton(btnCancel)
        btnStdSizer.AddButton(btnSave)
        btnStdSizer.AddButton(btnApply)
        btnStdSizer.Realize()
        
        sizer.Add(item=btnStdSizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)

        self.SetSizer(sizer)
        sizer.Fit(self)

    def UpdateSettings(self):
        idx = 0
        for r in self.raster.itervalues():
            r['prop']['pcolor'] = self.FindWindowById(self.wxId['pcolor'][idx]).GetColour()
            r['prop']['pwidth'] = int(self.FindWindowById(self.wxId['pwidth'][idx]).GetValue())
            r['prop']['pstyle'] = self.FindWindowById(self.wxId['pstyle'][idx]).GetStringSelection()
            r['plegend'] = self.FindWindowById(self.wxId['plegend'][idx]).GetValue()
            idx +=1

        self.properties['marker']['color'] = self.FindWindowById(self.wxId['marker']['color']).GetColour()
        self.properties['marker']['fill'] = self.FindWindowById(self.wxId['marker']['fill']).GetStringSelection()
        self.properties['marker']['size'] = self.FindWindowById(self.wxId['marker']['size']).GetValue()
        self.properties['marker']['type'] = self.FindWindowById(self.wxId['marker']['type']).GetValue()
        self.properties['marker']['legend'] = self.FindWindowById(self.wxId['marker']['legend']).GetValue()

        for axis in ('x-axis', 'y-axis'):
            self.properties[axis]['prop']['type'] = self.FindWindowById(self.wxId[axis]['type']).GetValue()
            self.properties[axis]['prop']['min'] = float(self.FindWindowById(self.wxId[axis]['min']).GetValue())
            self.properties[axis]['prop']['max'] = float(self.FindWindowById(self.wxId[axis]['max']).GetValue())
            self.properties[axis]['prop']['log'] = self.FindWindowById(self.wxId[axis]['log']).IsChecked()

        self.properties['grid']['color'] = self.FindWindowById(self.wxId['grid']['color']).GetColour()
        self.properties['grid']['enabled'] = self.FindWindowById(self.wxId['grid']['enabled']).IsChecked()

        self.properties['font']['prop']['legendSize'] = self.FindWindowById(self.wxId['font']['legendSize']).GetValue()
        self.properties['legend']['enabled'] = self.FindWindowById(self.wxId['legend']['enabled']).IsChecked()

    def OnSave(self, event):
        """Button 'Save' pressed"""
        self.UpdateSettings()
        fileSettings = {}
        UserSettings.ReadSettingsFile(settings=fileSettings)
        fileSettings['profile'] = UserSettings.Get(group='profile')
        file = UserSettings.SaveToFile(fileSettings)
        self.parent.parent.gismanager.goutput.WriteLog(_('Profile settings saved to file \'%s\'.') % file)
        self.Close()

    def OnApply(self, event):
        """Button 'Apply' pressed"""
        self.UpdateSettings()
        self.Close()

    def OnCancel(self, event):
        """Button 'Cancel' pressed"""
        self.Close()
